package com.cathaypacific.facebook.login.widget

/**
 * Created by roy.zhiqiang.huang on 4/6/2018.
 *
 *
 * Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
 *
 *
 * You are hereby granted a non-exclusive, worldwide, royalty-free license to use,
 * copy, modify, and distribute this software in source code or binary form for use
 * in connection with the web services and APIs provided by Facebook.
 *
 *
 * As with any software that integrates with the Facebook platform, your use of
 * this software is subject to the Facebook Developer Principles and Policies
 * [http://developers.facebook.com/policy/]. This copyright notice shall be
 * included in all copies or substantial portions of the software.
 *
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 *
 *
 * Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
 *
 *
 * You are hereby granted a non-exclusive, worldwide, royalty-free license to use,
 * copy, modify, and distribute this software in source code or binary form for use
 * in connection with the web services and APIs provided by Facebook.
 *
 *
 * As with any software that integrates with the Facebook platform, your use of
 * this software is subject to the Facebook Developer Principles and Policies
 * [http://developers.facebook.com/policy/]. This copyright notice shall be
 * included in all copies or substantial portions of the software.
 *
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
/**
 * Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
 *
 * You are hereby granted a non-exclusive, worldwide, royalty-free license to use,
 * copy, modify, and distribute this software in source code or binary form for use
 * in connection with the web services and APIs provided by Facebook.
 *
 * As with any software that integrates with the Facebook platform, your use of
 * this software is subject to the Facebook Developer Principles and Policies
 * [http://developers.facebook.com/policy/]. This copyright notice shall be
 * included in all copies or substantial portions of the software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

import android.app.AlertDialog
import android.content.Context
import android.graphics.Canvas
import android.os.Bundle
import android.support.v7.content.res.AppCompatResources
import android.util.AttributeSet
import android.view.View

import com.facebook.AccessToken
import com.facebook.AccessTokenTracker
import com.facebook.CallbackManager
import com.facebook.FacebookButtonBase
import com.facebook.FacebookCallback
import com.facebook.FacebookSdk
import com.facebook.Profile
import com.facebook.appevents.AppEventsLogger
import com.facebook.internal.AnalyticsEvents
import com.facebook.internal.CallbackManagerImpl
import com.facebook.internal.FetchedAppSettings
import com.facebook.internal.FetchedAppSettingsManager
import com.facebook.internal.LoginAuthorizationType
import com.facebook.internal.Utility
import com.facebook.login.DefaultAudience
import com.facebook.login.LoginBehavior
import com.facebook.login.LoginManager
import com.facebook.login.LoginResult
import com.facebook.login.R
import com.facebook.login.widget.ToolTipPopup

import java.util.Arrays

/**
 * A Log In/Log Out button that maintains login state and logs in/out for the app.
 *
 *
 * This control requires the app ID to be specified in the AndroidManifest.xml.
 */
class LoginButton : FacebookButtonBase {

    internal var logOutListen: LogOutListen? = null
    private var confirmLogout: Boolean = false
    private var loginText: String? = null
    private var logoutText: String? = null
    private var properties = LoginButtonProperties()
    private val loginLogoutEventName = AnalyticsEvents.EVENT_LOGIN_VIEW_USAGE
    private var toolTipChecked: Boolean = false
    private var toolTipStyle: ToolTipPopup.Style = ToolTipPopup.Style.BLUE
    /**
     * Return the current [ToolTipMode] for this LoginButton
     *
     * @return The [ToolTipMode]
     */
    /**
     * Sets the mode of the Tool Tip popup. Currently supported modes are default (normal
     * behavior), always_on (popup remains up until forcibly dismissed), and always_off (popup
     * doesn't show)
     *
     * @param toolTipMode The new mode for the tool tip
     */
    var toolTipMode: ToolTipMode? = null
    /**
     * Gets the current amount of time (in ms) that the tool tip will be displayed to the user.
     *
     * @return The current amount of time (in ms) that the tool tip will be displayed.
     */
    /**
     * Sets the amount of time (in milliseconds) that the tool tip will be shown to the user. The
     * default is {@value ToolTipPopup#DEFAULT_POPUP_DISPLAY_TIME}.
     * Any value that is less than or equal to zero will cause the tool tip to be displayed
     * indefinitely.
     *
     * @param displayTime The amount of time (in milliseconds) that the tool tip will be displayed
     * to the user
     */
    var toolTipDisplayTime = ToolTipPopup.DEFAULT_POPUP_DISPLAY_TIME
    private var toolTipPopup: ToolTipPopup? = null
    private var accessTokenTracker: AccessTokenTracker? = null
    internal var loginManager: LoginManager? = null
        get() {
            if (field == null) {
                this.loginManager = LoginManager.getInstance()
            }
            return field
        }

    /**
     * Gets the default audience to use when the user logs in.
     * This value is only useful when specifying publish permissions for the native
     * login dialog.
     *
     * @return the default audience value to use
     */
    /**
     * Sets the default audience to use when the user logs in.
     * This value is only useful when specifying publish permissions for the native
     * login dialog.
     *
     * @param defaultAudience the default audience value to use
     */
    var defaultAudience: DefaultAudience
        get() = properties.defaultAudience
        set(defaultAudience) {
            properties.defaultAudience = defaultAudience
        }

    /**
     * Gets the login behavior during authorization. If null is returned, the default
     * ([LoginBehavior.NATIVE_WITH_FALLBACK][LoginBehavior]
     * will be used.
     *
     * @return loginBehavior The [LoginBehavior] that
     * specifies what behaviors should be attempted during
     * authorization.
     */
    /**
     * Sets the login behavior during authorization. If null is specified, the default
     * ([LoginBehavior.NATIVE_WITH_FALLBACK][LoginBehavior]
     * will be used.
     *
     * @param loginBehavior The [LoginBehavior] that
     * specifies what behaviors should be attempted during
     * authorization.
     */
    var loginBehavior: LoginBehavior
        get() = properties.loginBehavior
        set(loginBehavior) {
            properties.loginBehavior = loginBehavior
        }

    // For testing purposes only
    internal val permissions: List<String>?
        get() = properties.permissions

    protected val newLoginClickListener: LoginClickListener
        get() = LoginClickListener()
    // ***
    // Keep all the enum values in sync with attrs.xml
    // ***

    /**
     * The display modes for the login button tool tip.
     */
    enum class ToolTipMode private constructor(private val stringValue: String, val value: Int) {
        /**
         * Default display mode. A server query will determine if the tool tip should be displayed
         * and, if so, what the string shown to the user should be.
         */
        AUTOMATIC("automatic", 0),

        /**
         * Display the tool tip with a local string--regardless of what the server returns
         */
        DISPLAY_ALWAYS("display_always", 1),

        /**
         * Never display the tool tip--regardless of what the server says
         */
        NEVER_DISPLAY("never_display", 2);

        override fun toString(): String {
            return stringValue
        }

        companion object {

            var DEFAULT = AUTOMATIC

            fun fromInt(enumValue: Int): ToolTipMode? {
                for (mode in values()) {
                    if (mode.value == enumValue) {
                        return mode
                    }
                }

                return null
            }
        }
    }

    internal class LoginButtonProperties {
        var defaultAudience = DefaultAudience.FRIENDS
        var permissions: List<String>? = emptyList()
            private set
        var authorizationType: LoginAuthorizationType? = null
        var loginBehavior = LoginBehavior.NATIVE_WITH_FALLBACK

        fun setReadPermissions(permissions: List<String>) {

            if (LoginAuthorizationType.PUBLISH == authorizationType) {
                throw UnsupportedOperationException("Cannot call setReadPermissions after " + "setPublishPermissions has been called.")
            }
            this.permissions = permissions
            authorizationType = LoginAuthorizationType.READ
        }

        fun setPublishPermissions(permissions: List<String>) {

            if (LoginAuthorizationType.READ == authorizationType) {
                throw UnsupportedOperationException("Cannot call setPublishPermissions after " + "setReadPermissions has been called.")
            }
            if (Utility.isNullOrEmpty(permissions)) {
                throw IllegalArgumentException(
                        "Permissions for publish actions cannot be null or empty.")
            }
            this.permissions = permissions
            authorizationType = LoginAuthorizationType.PUBLISH
        }

        fun clearPermissions() {
            permissions = null
            authorizationType = null
        }
    }

    /**
     * Create the LoginButton by inflating from XML
     *
     * @see View.View
     */
    constructor(context: Context) : super(
            context, null,
            0,
            0,
            AnalyticsEvents.EVENT_LOGIN_BUTTON_CREATE,
            AnalyticsEvents.EVENT_LOGIN_BUTTON_DID_TAP) {
    }

    /**
     * Create the LoginButton by inflating from XML
     *
     * @see View.View
     */
    constructor(context: Context, attrs: AttributeSet) : super(
            context,
            attrs,
            0,
            0,
            AnalyticsEvents.EVENT_LOGIN_BUTTON_CREATE,
            AnalyticsEvents.EVENT_LOGIN_BUTTON_DID_TAP) {
    }

    /**
     * Create the LoginButton by inflating from XML and applying a style.
     *
     * @see View.View
     */
    constructor(context: Context, attrs: AttributeSet, defStyle: Int) : super(
            context,
            attrs,
            defStyle,
            0,
            AnalyticsEvents.EVENT_LOGIN_BUTTON_CREATE,
            AnalyticsEvents.EVENT_LOGIN_BUTTON_DID_TAP) {
    }

    /**
     * Set the permissions to use when the user logs in. The permissions here
     * can only be read permissions. If any publish permissions are included, the login
     * attempt by the user will fail. The LoginButton can only be associated with either
     * read permissions or publish permissions, but not both. Calling both
     * setReadPermissions and setPublishPermissions on the same instance of LoginButton
     * will result in an exception being thrown unless clearPermissions is called in between.
     *
     *
     * This method is only meaningful if called before the user logs in. If this is called
     * after login, and the list of permissions passed in is not a subset
     * of the permissions granted during the authorization, it will log an error.
     *
     *
     * It's important to always pass in a consistent set of permissions to this method, or
     * manage the setting of permissions outside of the LoginButton class altogether
     * (by using the LoginManager explicitly).
     *
     * @param permissions the read permissions to use
     * @throws UnsupportedOperationException if setPublishPermissions has been called
     */
    fun setReadPermissions(permissions: List<String>) {
        properties.setReadPermissions(permissions)
    }

    /**
     * Set the permissions to use when the user logs in. The permissions here
     * can only be read permissions. If any publish permissions are included, the login
     * attempt by the user will fail. The LoginButton can only be associated with either
     * read permissions or publish permissions, but not both. Calling both
     * setReadPermissions and setPublishPermissions on the same instance of LoginButton
     * will result in an exception being thrown unless clearPermissions is called in between.
     *
     *
     * This method is only meaningful if called before the user logs in. If this is called
     * after login, and the list of permissions passed in is not a subset
     * of the permissions granted during the authorization, it will log an error.
     *
     *
     * It's important to always pass in a consistent set of permissions to this method, or
     * manage the setting of permissions outside of the LoginButton class altogether
     * (by using the LoginManager explicitly).
     *
     * @param permissions the read permissions to use
     * @throws UnsupportedOperationException if setPublishPermissions has been called
     */
    fun setReadPermissions(vararg permissions: String) {
        properties.setReadPermissions(Arrays.asList(*permissions))
    }


    /**
     * Set the permissions to use when the user logs in. The permissions here
     * should only be publish permissions. If any read permissions are included, the login
     * attempt by the user may fail. The LoginButton can only be associated with either
     * read permissions or publish permissions, but not both. Calling both
     * setReadPermissions and setPublishPermissions on the same instance of LoginButton
     * will result in an exception being thrown unless clearPermissions is called in between.
     *
     *
     * This method is only meaningful if called before the user logs in. If this is called
     * after login, and the list of permissions passed in is not a subset
     * of the permissions granted during the authorization, it will log an error.
     *
     *
     * It's important to always pass in a consistent set of permissions to this method, or
     * manage the setting of permissions outside of the LoginButton class altogether
     * (by using the LoginManager explicitly).
     *
     * @param permissions the publish permissions to use
     * @throws UnsupportedOperationException if setReadPermissions has been called
     * @throws IllegalArgumentException      if permissions is null or empty
     */
    fun setPublishPermissions(permissions: List<String>) {
        properties.setPublishPermissions(permissions)
    }

    /**
     * Set the permissions to use when the user logs in. The permissions here
     * should only be publish permissions. If any read permissions are included, the login
     * attempt by the user may fail. The LoginButton can only be associated with either
     * read permissions or publish permissions, but not both. Calling both
     * setReadPermissions and setPublishPermissions on the same instance of LoginButton
     * will result in an exception being thrown unless clearPermissions is called in between.
     *
     *
     * This method is only meaningful if called before the user logs in. If this is called
     * after login, and the list of permissions passed in is not a subset
     * of the permissions granted during the authorization, it will log an error.
     *
     *
     * It's important to always pass in a consistent set of permissions to this method, or
     * manage the setting of permissions outside of the LoginButton class altogether
     * (by using the LoginManager explicitly).
     *
     * @param permissions the publish permissions to use
     * @throws UnsupportedOperationException if setReadPermissions has been called
     * @throws IllegalArgumentException      if permissions is null or empty
     */
    fun setPublishPermissions(vararg permissions: String) {
        properties.setPublishPermissions(Arrays.asList(*permissions))
    }


    /**
     * Clears the permissions currently associated with this LoginButton.
     */
    fun clearPermissions() {
        properties.clearPermissions()
    }

    /**
     * Sets the style (background) of the Tool Tip popup. Currently a blue style and a black
     * style are supported. Blue is default
     *
     * @param toolTipStyle The style of the tool tip popup.
     */
    fun setToolTipStyle(toolTipStyle: ToolTipPopup.Style) {
        this.toolTipStyle = toolTipStyle
    }

    /**
     * Dismisses the Tooltip if it is currently visible
     */
    fun dismissToolTip() {
        if (toolTipPopup != null) {
            toolTipPopup!!.dismiss()
            toolTipPopup = null
        }
    }

    /**
     * Registers a login callback to the given callback manager.
     *
     * @param callbackManager The callback manager that will encapsulate the callback.
     * @param callback        The login callback that will be called on login completion.
     */
    fun registerCallback(
            callbackManager: CallbackManager,
            callback: FacebookCallback<LoginResult>) {
        loginManager?.registerCallback(callbackManager, callback)
    }

    /**
     * Registers a login callback to the given callback manager.
     *
     * @param callbackManager The callback manager that will encapsulate the callback.
     * @param callback        The login callback that will be called on login completion.
     */
    fun registerCallback(
            callbackManager: CallbackManager,
            callback: FacebookCallback<LoginResult>, logOutListen: LogOutListen) {
        this.logOutListen = logOutListen
        loginManager?.registerCallback(callbackManager, callback)
    }

    /**
     * Unregisters a login callback to the given callback manager.
     *
     * @param callbackManager The callback manager that will encapsulate the callback.
     */
    fun unregisterCallback(callbackManager: CallbackManager) {
        loginManager?.unregisterCallback(callbackManager)
    }

    override fun onAttachedToWindow() {
        super.onAttachedToWindow()
        if (accessTokenTracker != null && !accessTokenTracker!!.isTracking) {
            accessTokenTracker!!.startTracking()
            setButtonText()
        }
    }

    override fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)

        if (!toolTipChecked && !isInEditMode) {
            toolTipChecked = true
            checkToolTipSettings()
        }
    }

    private fun showToolTipPerSettings(settings: FetchedAppSettings?) {
        if (settings != null && settings.nuxEnabled && visibility == View.VISIBLE) {
            val toolTipString = settings.nuxContent
            displayToolTip(toolTipString)
        }
    }

    private fun displayToolTip(toolTipString: String) {
        toolTipPopup = ToolTipPopup(toolTipString, this)
        toolTipPopup!!.setStyle(toolTipStyle)
        toolTipPopup!!.setNuxDisplayTime(toolTipDisplayTime)
        toolTipPopup!!.show()
    }

    private fun checkToolTipSettings() {
        when (toolTipMode) {
            LoginButton.ToolTipMode.AUTOMATIC -> {
                // kick off an async request
                val appId = Utility.getMetadataApplicationId(context)
                FacebookSdk.getExecutor().execute {
                    val settings = FetchedAppSettingsManager.queryAppSettings(appId, false)
                    activity.runOnUiThread { showToolTipPerSettings(settings) }
                }
            }
            LoginButton.ToolTipMode.DISPLAY_ALWAYS -> {
                val toolTipString = resources.getString(
                        R.string.com_facebook_tooltip_default)
                displayToolTip(toolTipString)
            }
            LoginButton.ToolTipMode.NEVER_DISPLAY -> {
            }
        }
    }

    override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
        super.onLayout(changed, left, top, right, bottom)
        setButtonText()
    }

    override fun onDetachedFromWindow() {
        super.onDetachedFromWindow()
        if (accessTokenTracker != null) {
            accessTokenTracker!!.stopTracking()
        }
        dismissToolTip()
    }

    override fun onVisibilityChanged(changedView: View, visibility: Int) {
        super.onVisibilityChanged(changedView, visibility)
        // If the visibility is not VISIBLE, we want to dismiss the tooltip if it is there
        if (visibility != View.VISIBLE) {
            dismissToolTip()
        }
    }

    internal fun setProperties(properties: LoginButtonProperties) {
        this.properties = properties
    }

    override fun configureButton(
            context: Context,
            attrs: AttributeSet?,
            defStyleAttr: Int,
            defStyleRes: Int) {
        super.configureButton(context, attrs, defStyleAttr, defStyleRes)
        setInternalOnClickListener(newLoginClickListener)

        parseLoginButtonAttributes(context, attrs, defStyleAttr, defStyleRes)

        if (isInEditMode) {
            // cannot use a drawable in edit mode, so setting the background color instead
            // of a background resource.
            setBackgroundColor(resources.getColor(com.facebook.common.R.color.com_facebook_blue))
            // hardcoding in edit mode as getResources().getString() doesn't seem to work in
            // IntelliJ
            loginText = "Continue with Facebook"
        } else {
            accessTokenTracker = object : AccessTokenTracker() {
                override fun onCurrentAccessTokenChanged(
                        oldAccessToken: AccessToken?,
                        currentAccessToken: AccessToken?) {
                    setButtonText()
                }
            }
        }

        setButtonText()

        // set vector drawables on the button
        setCompoundDrawablesWithIntrinsicBounds(
                AppCompatResources.getDrawable(getContext(), R.drawable.com_facebook_button_login_logo), null, null, null)
    }

    override fun getDefaultStyleResource(): Int {
        return R.style.com_facebook_loginview_default_style
    }

    private fun parseLoginButtonAttributes(
            context: Context,
            attrs: AttributeSet?,
            defStyleAttr: Int,
            defStyleRes: Int) {
        this.toolTipMode = ToolTipMode.DEFAULT
        val a = context.theme.obtainStyledAttributes(
                attrs,
                R.styleable.com_facebook_login_view,
                defStyleAttr,
                defStyleRes)
        try {
            confirmLogout = a.getBoolean(R.styleable.com_facebook_login_view_com_facebook_confirm_logout, true)
            loginText = a.getString(R.styleable.com_facebook_login_view_com_facebook_login_text)
            logoutText = a.getString(R.styleable.com_facebook_login_view_com_facebook_logout_text)
            toolTipMode = ToolTipMode.fromInt(a.getInt(
                    R.styleable.com_facebook_login_view_com_facebook_tooltip_mode,
                    ToolTipMode.DEFAULT.value))
        } finally {
            a.recycle()
        }
    }

    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        val fontMetrics = paint.fontMetrics
        val height = compoundPaddingTop +
                Math.ceil((Math.abs(fontMetrics.top) + Math.abs(fontMetrics.bottom)).toDouble()).toInt() +
                compoundPaddingBottom

        val resources = resources
        var text = loginText
        var logInWidth: Int
        var width: Int
        if (text == null) {
            text = resources.getString(R.string.com_facebook_loginview_log_in_button_continue)
            logInWidth = measureButtonWidth()
            width = View.resolveSize(logInWidth, widthMeasureSpec)
            if (width < logInWidth) {
                text = resources.getString(R.string.com_facebook_loginview_log_in_button)
            }
        }
        logInWidth = measureButtonWidth()

        text = logoutText
        if (text == null) {
            text = resources.getString(R.string.com_facebook_loginview_log_out_button)
        }
        val logOutWidth = measureButtonWidth()

        width = View.resolveSize(Math.max(logInWidth, logOutWidth), widthMeasureSpec)
        setMeasuredDimension(width, height)
    }

    private fun measureButtonWidth(): Int {
        return compoundPaddingLeft
        //        getCompoundDrawablePadding();
        //                textWidth +
        //                getCompoundPaddingRight());
    }

    private fun setButtonText() {
        val resources = resources
        if (!isInEditMode && AccessToken.getCurrentAccessToken() != null) {
            //            setText((logoutText != null) ?
            //                    logoutText :
            //                    resources.getString(R.string.com_facebook_loginview_log_out_button));
        } else {
            if (loginText != null) {
                text = loginText
            } else {
                //                String text = resources.getString(
                //                        R.string.com_facebook_loginview_log_in_button_continue);
                val width = width
                // if the width is 0, we are going to measure size, so use the long text
                if (width != 0) {
                    // we have a specific width, check if the long text fits
                    val measuredWidth = measureButtonWidth()
                    if (measuredWidth > width) {
                        // it doesn't fit, use the shorter text
                        //                        text = resources.getString(R.string.com_facebook_loginview_log_in_button);
                    }
                }
                text = ""
            }
        }
    }

    override fun getDefaultRequestCode(): Int {
        return CallbackManagerImpl.RequestCodeOffset.Login.toRequestCode()
    }

    protected inner class LoginClickListener : View.OnClickListener {

        protected val loginManager: LoginManager
            get() {
                val manager = LoginManager.getInstance()
                manager.defaultAudience = defaultAudience
                manager.loginBehavior = loginBehavior
                return manager
            }

        override fun onClick(v: View) {
            callExternalOnClickListener(v)

            val accessToken = AccessToken.getCurrentAccessToken()
            if (accessToken != null) {
                // Log out
                performLogout(context)
            } else {
                performLogin()
            }

            val logger = AppEventsLogger.newLogger(context)

            val parameters = Bundle()
            parameters.putInt("logging_in", if (accessToken != null) 0 else 1)

            logger.logSdkEvent(loginLogoutEventName, null, parameters)
        }

        protected fun performLogin() {
            val loginManager = loginManager
            if (LoginAuthorizationType.PUBLISH == properties.authorizationType) {
                if (this@LoginButton.fragment != null) {
                    loginManager.logInWithPublishPermissions(
                            this@LoginButton.fragment,
                            properties.permissions)
                } else if (this@LoginButton.nativeFragment != null) {
                    loginManager.logInWithPublishPermissions(
                            this@LoginButton.nativeFragment,
                            properties.permissions)
                } else {
                    loginManager.logInWithPublishPermissions(
                            this@LoginButton.activity,
                            properties.permissions)
                }
            } else {
                if (this@LoginButton.fragment != null) {
                    loginManager.logInWithReadPermissions(
                            this@LoginButton.fragment,
                            properties.permissions)
                } else if (this@LoginButton.nativeFragment != null) {
                    loginManager.logInWithReadPermissions(
                            this@LoginButton.nativeFragment,
                            properties.permissions)
                } else {
                    loginManager.logInWithReadPermissions(
                            this@LoginButton.activity,
                            properties.permissions)
                }
            }
        }

        protected fun performLogout(context: Context) {
            val loginManager = loginManager
            if (confirmLogout) {
                // Create a confirmation dialog
                val logout = resources.getString(
                        R.string.com_facebook_loginview_log_out_action)
                val cancel = resources.getString(
                        R.string.com_facebook_loginview_cancel_action)
                val message: String
                val profile = Profile.getCurrentProfile()
                if (profile != null && profile.name != null) {
                    message = String.format(
                            resources.getString(
                                    R.string.com_facebook_loginview_logged_in_as),
                            profile.name)
                } else {
                    message = resources.getString(
                            R.string.com_facebook_loginview_logged_in_using_facebook)
                }
                val builder = AlertDialog.Builder(context)
                builder.setMessage(message)
                        .setCancelable(true)
                        .setPositiveButton(logout) { dialog, which ->
                            loginManager.logOut()
                            if (logOutListen != null) {
                                logOutListen!!.onLogOut()
                            }
                        }
                        .setNegativeButton(cancel, null)
                builder.create().show()
            } else {
                loginManager.logOut()
            }
        }
    }

    companion object {

        private val TAG = com.facebook.login.widget.LoginButton::class.java.name
    }
}
